package com.vpen.test.demo.controller;

import cn.hutool.core.util.RandomUtil;
import com.vpen.clib.result.CResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * 描述
 *
 * @author 韦鹏
 * @date 2022/8/26 14:54
 */
@Slf4j
@RestController
@RequestMapping("/async")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class CompletableFutureController {


    @GetMapping("combine")
    public CResult<HashMap<String, Object>> test1() {

        long start = System.currentTimeMillis();
        log.debug("开始");
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            sleep(1, TimeUnit.SECONDS);
            log.debug("总数：查询所有数学总条数");
            return RandomUtil.randomInt(0, 10000);
        });

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
            sleep(1, TimeUnit.SECONDS);
            log.debug("总数：查询所有语文总条数");
            return RandomUtil.randomInt(0, 10000);
        });

        CompletableFuture<List<Integer>> future1List = CompletableFuture.supplyAsync(() -> {
            sleep(2, TimeUnit.SECONDS);
            log.debug("列表：查询所有数学列表");
            ArrayList<Integer> list = new ArrayList<>();
            list.add(123);
            list.add(456);
            return list;
        });

        CompletableFuture<List<Integer>> future2List = CompletableFuture.supplyAsync(() -> {
            sleep(2, TimeUnit.SECONDS);
            log.debug("列表：查询所有语文列表");
            ArrayList<Integer> list = new ArrayList<>();
            list.add(678);
            list.add(891);
            return list;
        });


        // 合并结果
        CompletableFuture<HashMap<String, Integer>> combine = future1.thenCombine(future2, (total1, total2) -> {
            HashMap<String, Integer> map = new HashMap<>(2);
            map.put("future1", total1);
            map.put("future2", total2);
            log.debug("合并总条数");
            return map;
        });


        CompletableFuture<HashMap<String, List<Integer>>> listCombine = future1List.thenCombine(future2List, (l1, l2) -> {
            HashMap<String, List<Integer>> map = new HashMap<>(2);
            map.put("future1List", l1);
            map.put("future2List", l2);
            log.debug("合并总列表");
            return map;
        });


        log.debug("结束");
        HashMap<String, Integer> totalMap = combine.join();
        HashMap<String, List<Integer>> listMap = listCombine.join();
        log.debug("全部结束:耗时：{}", System.currentTimeMillis() - start);

        HashMap<String, Object> map = new HashMap<>(2);
        map.put("total", totalMap);
        map.put("list", listMap);
        return CResult.success(map);
    }


    @GetMapping("allof")
    public CResult<String> test2() {

        long start = System.currentTimeMillis();
        log.debug("开始");
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            sleep(1, TimeUnit.SECONDS);
            log.debug("总数：查询所有数学总条数");
            return RandomUtil.randomInt(0, 10000);
        });

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
            sleep(1, TimeUnit.SECONDS);
            log.debug("总数：查询所有语文总条数");
            return RandomUtil.randomInt(0, 10000);
        });

        CompletableFuture<List<Integer>> future1List = CompletableFuture.supplyAsync(() -> {
            sleep(2, TimeUnit.SECONDS);
            log.debug("列表：查询所有数学列表");
            ArrayList<Integer> list = new ArrayList<>();
            list.add(123);
            list.add(456);
            return list;
        });

        CompletableFuture<List<Integer>> future2List = CompletableFuture.supplyAsync(() -> {
            sleep(2, TimeUnit.SECONDS);
            log.debug("列表：查询所有语文列表");
            ArrayList<Integer> list = new ArrayList<>();
            list.add(678);
            list.add(891);
            return list;
        });
        // 等待所有线程执行
        CompletableFuture.allOf(future1, future2, future1List, future2List).join();
        log.debug("全部结束:耗时：{}", System.currentTimeMillis() - start);
        return CResult.success();
    }

    @GetMapping("run")
    public CResult<String> test3() {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            sleep(2000, TimeUnit.MILLISECONDS);
        });

        future.whenComplete((r, ex) -> {
            log.debug("处理完成");
        });


        log.debug("hello");
        return CResult.success();
    }

    @GetMapping("thenApply2")
    public CResult<String> test42() {
        // thenApply 当计算完成的时候请执行某个 function
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            sleep(1, TimeUnit.SECONDS);
            return 2;
        });
        // 当计算完future,执行power方法并转换成字符,前一个 stage 完成后继续执行
        CompletableFuture<String> res = future.thenApplyAsync(x -> {
            sleep(2, TimeUnit.SECONDS);
            int i = 1 / 0;// 异常
            return power(x);
        }).thenApply(x -> {
            sleep(3, TimeUnit.SECONDS);
            return x.toString();
        });
        return CResult.success(res.join());
    }

    @GetMapping("thenApply")
    public CResult<String> test4() {
        // thenApply 当计算完成的时候请执行某个 function
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 2);
        // 当计算完future,执行power方法并转换
        CompletableFuture<String> res = future.thenApply(this::power).thenApplyAsync(Object::toString);
        return CResult.success(res.join());
    }


    @GetMapping("handle")
    public CResult<String> test5() {
        // handle 方法会处理正常计算值和异常，可以屏蔽异常，避免异常继续抛出
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 2);

        CompletableFuture<String> handleAsync = future.handle((r, ex) -> {
            log.debug(String.valueOf(ex));
            int i = 1 / 0;// 异常
            return r * r;
        }).handleAsync((r, ex) -> {
            log.debug(String.valueOf(ex));
            if (r == null) {
                return null;
            }
            return r.toString();
        });
        return CResult.success(handleAsync.join());
    }

    private Integer power(Integer x) {
        return x * x;
    }


    static void sleep(int t, TimeUnit u) {
        try {
            log.debug("sleep开始");
            u.sleep(t);
            log.debug("sleep结束");
        } catch (InterruptedException e) {
            log.debug("中断异常");
        }
    }

}
